#include "door_bell_sound.h"

#define ES8311_I2C_PORT I2C_NUM_0
#define I2C_SCL_PIN 1
#define I2C_SDA_PIN 0

#define I2S_MCK_PIN 3
#define I2S_BCK_PIN 2
#define I2S_DATA_WS_PIN 5
#define I2S_DATA_OUT_PIN 6
#define I2S_DATA_IN_PIN 4
i2s_chan_handle_t speekerHandle;
i2s_chan_handle_t micHandle;

#define PA_GPIO 46

esp_codec_dev_sample_info_t fs;
esp_codec_dev_handle_t codec_dev;

// I2C Init
i2c_master_bus_handle_t i2c_bus_handle;
static void door_bell_sound_I2C_Init(void)
{
    i2c_master_bus_config_t i2c_bus_config = {0};
    i2c_bus_config.clk_source = I2C_CLK_SRC_DEFAULT;
    i2c_bus_config.i2c_port = ES8311_I2C_PORT;
    i2c_bus_config.scl_io_num = I2C_SCL_PIN;
    i2c_bus_config.sda_io_num = I2C_SDA_PIN;
    i2c_bus_config.glitch_ignore_cnt = 7;
    i2c_bus_config.flags.enable_internal_pullup = true; // 是否内部上拉
    i2c_new_master_bus(&i2c_bus_config, &i2c_bus_handle);
}

// I2S Init
static void door_bell_sound_I2S_Init(void)
{
    i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_0, I2S_ROLE_MASTER);
    i2s_std_config_t std_cfg = {
        .clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(16000 /* sample rate*/),
        .slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(16 /* sample deep */, I2S_SLOT_MODE_STEREO /* 单声道或双声道 */),
        .gpio_cfg = {
            .mclk = I2S_MCK_PIN,
            .bclk = I2S_BCK_PIN,
            .ws = I2S_DATA_WS_PIN,
            .dout = I2S_DATA_OUT_PIN,
            .din = I2S_DATA_IN_PIN,
        },
    };

    // create channel
    i2s_new_channel(&chan_cfg, &speekerHandle, &micHandle);

    // Init channel
    i2s_channel_init_std_mode(speekerHandle, &std_cfg);
    i2s_channel_init_std_mode(micHandle, &std_cfg);

    // enable channel
    i2s_channel_enable(speekerHandle);
    i2s_channel_enable(micHandle);
}

// ES8311 config
static void door_bell_sound_ES8311_Config(void)
{
    audio_codec_i2s_cfg_t i2s_cfg = {

        .rx_handle = micHandle,
        .tx_handle = speekerHandle,

    };
    const audio_codec_data_if_t *data_if = audio_codec_new_i2s_data(&i2s_cfg);

    audio_codec_i2c_cfg_t i2c_cfg = {
        .addr = ES8311_CODEC_DEFAULT_ADDR,
        .port = ES8311_I2C_PORT,
        .bus_handle = i2c_bus_handle};
    const audio_codec_ctrl_if_t *out_ctrl_if = audio_codec_new_i2c_ctrl(&i2c_cfg);

    const audio_codec_gpio_if_t *gpio_if = audio_codec_new_gpio();

    // 创建编码器接口
    es8311_codec_cfg_t es8311_cfg = {
        .codec_mode = ESP_CODEC_DEV_WORK_MODE_BOTH, // 编码器工作模式：录音和播放
        .ctrl_if = out_ctrl_if,
        .gpio_if = gpio_if,
        .pa_pin = PA_GPIO,
        .use_mclk = true,
        .digital_mic = false};
    const audio_codec_if_t *out_codec_if = es8311_codec_new(&es8311_cfg);

    /**
     * @brief Codec device configuration
     */
    esp_codec_dev_cfg_t dev_cfg = {
        .codec_if = out_codec_if,              // codec interface from es8311_codec_new
        .data_if = data_if,                    // data interface from audio_codec_new_i2s_data
        .dev_type = ESP_CODEC_DEV_TYPE_IN_OUT, // codec support both playback and record
    };
    codec_dev = esp_codec_dev_new(&dev_cfg);

    // Below code shows how to play
    esp_codec_dev_set_out_vol(codec_dev, 60.0);
    fs.sample_rate = 16000;
    fs.channel = 1;
    fs.bits_per_sample = 16;
    fs.channel_mask = ESP_CODEC_DEV_MAKE_CHANNEL_MASK(0);

    // Below code shows how to record
    esp_codec_dev_set_in_gain(codec_dev, 40.0);
}

void door_bell_sound_Open(void)
{
    esp_codec_dev_open(codec_dev, &fs);
}

void door_bell_sound_Close(void)
{
    esp_codec_dev_close(codec_dev);
}

int door_bell_sound_Read(uint8_t *data, int dataLen)
{
    if (codec_dev && data && dataLen)
    {
        return esp_codec_dev_read(codec_dev, data, dataLen);
    }

    return ESP_CODEC_DEV_READ_FAIL;
}

/**
 * @description: 向es8311写数据
 * @param {uint8_t} *data 要写入的数据
 * @param {int} dataLen 要写入的数据长度
 * @return {*} ESP_CODEC_DEV_OK: Read success
 *                ESP_CODEC_DEV_INVALID_ARG: Invalid arguments
 *                ESP_CODEC_DEV_NOT_SUPPORT: Codec not support
 *                ESP_CODEC_DEV_WRONG_STATE: Driver not open yet
 *                ESP_CODEC_DEV_READ_FAIL
 */
int door_bell_sound_Write(uint8_t *data, int dataLen)
{
    if (codec_dev && data && dataLen)
    {
        return esp_codec_dev_write(codec_dev, data, dataLen);
    }

    return ESP_CODEC_DEV_WRITE_FAIL;
}

void door_bell_sound_Init(void)
{
    // I2C Init
    door_bell_sound_I2C_Init();

    // I2S Init
    door_bell_sound_I2S_Init();

    // ES8311 config
    door_bell_sound_ES8311_Config();
}
